{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "text": [
      "[[ 0.05835258 -0.41259393 -0.27921709]\n",
      " [ 0.01632928  0.24739441 -0.03040825]\n",
      " [ 0.20268691  0.4733998   0.24627307]]\n",
      "[[ 0.02767221 -0.86693538 -0.80150556]\n",
      " [-0.55412169  0.15211384 -0.02488487]\n",
      " [ 1.25523448  0.44817592  0.02383145]\n",
      " [-0.02536285 -0.05911647 -0.1390149 ]]\n",
      "[0. 1. 0. 0. 0. 0. 0. 0. 0. 0.]\n"
     ],
     "output_type": "stream"
    },
    {
     "data": {
      "text/plain": "<Figure size 432x288 with 1 Axes>",
      "image/png": "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\n"
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# test\n",
    "import numpy as np\n",
    "from matplotlib import pyplot as plt\n",
    "\n",
    "a = np.array([\n",
    "    [1, 2],\n",
    "    [9, 0],\n",
    "    [0, 12]\n",
    "])\n",
    "\n",
    "plt.imshow(a, interpolation='nearest')\n",
    "print(np.random.rand(3, 3) - 0.5)\n",
    "print(np.random.normal(loc=0.0, scale=pow(3, -0.5), size=(4, 3)))\n",
    "test = np.zeros(10)"
   ]
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 下载训练集\n",
    "训练集csv100行 https://raw.githubusercontent.com/makeyourownneuralnetwork/makeyourownneuralnetwork/master/mnist_dataset/mnist_train_100.csv\n",
    "测试集sv10行 https://raw.githubusercontent.com/makeyourownneuralnetwork/makeyourownneuralnetwork/master/mnist_dataset/mnist_test_10.csv\n",
    "每行第一位是标签，后28*28=784的rgb像素绘制了数字笔迹。"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "outputs": [
    {
     "name": "stdout",
     "text": [
      "测试集第一条样本给出的结果 7\n",
      "最终结果 [[0.09306821]\n",
      " [0.0035355 ]\n",
      " [0.03231495]\n",
      " [0.07142326]\n",
      " [0.06563021]\n",
      " [0.01834562]\n",
      " [0.01358272]\n",
      " [0.92021875]\n",
      " [0.03953362]\n",
      " [0.02877203]]\n"
     ],
     "output_type": "stream"
    },
    {
     "data": {
      "text/plain": "<Figure size 432x288 with 1 Axes>",
      "image/png": "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\n"
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 主要内容\n",
    "import numpy as np\n",
    "import scipy.special\n",
    "from matplotlib import pyplot as plt\n",
    "\n",
    "\n",
    "class NeuralNetwork:\n",
    "    def __init__(self, input_nodes, hidden_nodes, output_nodes,\n",
    "                 learning_rate):\n",
    "        \"\"\"初始化 输入层、隐藏层、输出层节点\"\"\"\n",
    "        # 每层layer节点\n",
    "        self.input_nodes = input_nodes\n",
    "        self.hidden_nodes = hidden_nodes\n",
    "        self.output_nodes = output_nodes\n",
    "        self.learning_rate = learning_rate\n",
    "        self.activation_function = lambda x: scipy.special.expit(x)     # s激活函数\n",
    "        \n",
    "        # 连接layer之间的节点权重    w11 w21, w21 w22  根据推导原理，ih层矩阵行列应该是hidden_nodes*input_nodes，而不是i*h\n",
    "        # np.random.rand(3, 3) - 0.5   矩阵向量操作，生成3x️3矩阵 -0.5~0.5随机值。normal()正太分布改善。\n",
    "        # self.weight_input_hidden = (np.random.rand(self.hidden_nodes, self.input_nodes) - 0.5)\n",
    "        # self.weight_hidden_output = (np.random.rand(self.output_nodes, self.hidden_nodes) - 0.5)\n",
    "        self.weight_input_hidden = (\n",
    "            np.random.normal(loc=0.0, scale=pow(self.hidden_nodes, -0.5), size=(self.hidden_nodes, self.input_nodes)))\n",
    "        self.weight_hidden_output = (\n",
    "            np.random.normal(loc=0.0, scale=pow(self.output_nodes, -0.5), size=(self.output_nodes, self.hidden_nodes)))\n",
    "        \n",
    "    def train(self, inputs_list, targets_list):\n",
    "        # 根据样本训练，调整权重\n",
    "        # 1. 根据输入得出输出，跟query()方法类似\n",
    "        inputs = np.array(inputs_list, ndmin=2).T   # 第一层输入\n",
    "        targets = np.array(targets_list, ndmin=2).T     # 样本结果\n",
    "        hidden_inputs = np.dot(self.weight_input_hidden, inputs)    # 中间层输入\n",
    "        hidden_outputs = self.activation_function(hidden_inputs)\n",
    "        final_inputs = np.dot(self.weight_hidden_output, hidden_outputs)\n",
    "        final_outputs = self.activation_function(final_inputs)\n",
    "        # 2. 计算输出和样本预期结果差值，反馈更新权重\n",
    "        output_errors = targets -final_outputs    # 矩阵相减   第三层误差\n",
    "        hidden_errors = np.dot(self.weight_hidden_output.T, output_errors)  # 第二层误差\n",
    "        # 根据推导公式调整权重\n",
    "        self.weight_hidden_output += self.learning_rate * \\\n",
    "                                     np.dot((output_errors * final_outputs * (1-final_outputs)), np.transpose(hidden_outputs)) \n",
    "        self.weight_input_hidden += self.learning_rate * \\\n",
    "                                     np.dot((hidden_errors * hidden_outputs * (1-hidden_outputs)), np.transpose(inputs)) \n",
    "        \n",
    "    def query(self, inputs_list):\n",
    "        \"\"\" 预测 \"\"\"\n",
    "        # 输入列表转矩阵\n",
    "        inputs = np.array(inputs_list, ndmin=2).T\n",
    "        # I * W 得到第二层结果。S激活函数过滤得到第二层最终输出。\n",
    "        hidden_inputs = np.dot(self.weight_input_hidden, inputs)\n",
    "        hidden_outputs = self.activation_function(hidden_inputs)\n",
    "        # 第二层输出作为第三层输入。同理hidden层到output层\n",
    "        final_inputs = np.dot(self.weight_hidden_output, hidden_outputs)\n",
    "        final_outputs = self.activation_function(final_inputs)\n",
    "        return final_outputs\n",
    "        \n",
    "        \n",
    "        \n",
    "input_nodes = 784   # 训练集28*28个像素点\n",
    "hidden_nodes = 100  # 10～784之间一个合适的数\n",
    "output_nodes = 10   # 0～9十种可能\n",
    "learning_rate = 0.3\n",
    "\n",
    "nw = NeuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)\n",
    "# nw.query([1.0, 0.5, -1.5])\n",
    "\n",
    "# 先训练\n",
    "with open('./mnist_train_100.csv', 'r', encoding='utf-8') as f:\n",
    "    train_data_list = f.readlines()\n",
    "    \n",
    "for record in train_data_list:\n",
    "    all_values = record.split(',')  \n",
    "    inputs = np.asfarray(all_values[1:]) / 255.0 * 0.99 + 0.01  # 第一个值是结果，后面28*28个像素.转换rgb像素值0～255到矩阵值0～1。0会导致公示错误加0.01避免。\n",
    "    targets = np.zeros(output_nodes) + 0.01     # [0.01, ..., 0.01]  目标输出，正确label 0.99其它0.11\n",
    "    targets[int(all_values[0])] = 0.99\n",
    "    nw.train(inputs, targets)\n",
    "    \n",
    "# 然后简单测试 测试集第一条记录\n",
    "with open('./mnist_test_10.csv', 'r', encoding='utf-8') as f:\n",
    "    test_data_list = f.readlines()\n",
    "all_values = test_data_list[0].split(',')\n",
    "print('测试集第一条样本给出的结果', all_values[0])   # 7\n",
    "image_array = np.asfarray(all_values[1:]).reshape(28, 28)\n",
    "plt.imshow(image_array, cmap='Greys', interpolation='None')\n",
    "plt.show()\n",
    "# 预测结果 看看模型预测出的结果跟给出的结果是否一致\n",
    "final_outputs = nw.query(np.asfarray(all_values[1:]) / 255.0 + 0.01)\n",
    "print('最终结果', final_outputs)    # 输出矩阵第8行（对应数字7）信号最大，预测成功。\n",
    "# [[0.09306821]\n",
    "#  [0.0035355 ]\n",
    "#  [0.03231495]\n",
    "#  [0.07142326]\n",
    "#  [0.06563021]\n",
    "#  [0.01834562]\n",
    "#  [0.01358272]\n",
    "#  [0.92021875]\n",
    "#  [0.03953362]\n",
    "#  [0.02877203]]\n",
    "\n",
    "# 最终可以循环测试集，计算准确率。"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n",
     "is_executing": false
    }
   }
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.2"
  },
  "pycharm": {
   "stem_cell": {
    "cell_type": "raw",
    "source": [],
    "metadata": {
     "collapsed": false
    }
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}